package com.zhuhjay.utils;

import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import com.zhuhjay.security.LoginUserDetail;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.zhuhjay.constant.SecurityConstant.AUTH_RES_TITLE;

/**
 * @author ZhuHJay
 * @date 2023/1/11 14:33
 */
public class JwtUtils {
    /** 私钥 **/
    private static final String KEY = "secret-key:zhuhjay";
    /** token过期时间 **/
    public static final int EXPIRATION_TIME = 30 * 60;
    /** token过期时间单位 **/
    public static final TimeUnit TIME_UNIT = TimeUnit.SECONDS;
    /** 续签阈值, 当 0.25 > (剩余时间/总时间) 时将可续签
            即剩余时间为 1/4 时将进行续签 **/
    private static final BigDecimal THRESHOLD = new BigDecimal("0.25");

    /** 生成token **/
    public static String createToken(LoginUserDetail loginUserDetail) {
        Map<String, Object> payload = new HashMap<>(4);
        // 签发者
        payload.put(JWTPayload.ISSUER, "@ZhuHJay@");
        long uid = RedisIdWorker.nextId("token");
        payload.put("uid", uid);
        loginUserDetail.setUid(uid);
        // 设置过期时间
        LocalDateTime now = LocalDateTime.now();
        loginUserDetail.setLoginTime(now);
        loginUserDetail.setExpireTime(now.plusSeconds(TIME_UNIT.toSeconds(EXPIRATION_TIME)));
        return JWTUtil.createToken(payload, KEY.getBytes());
    }

    /** 获取用于响应的auth **/
    public static String takeRespAuth(String token) {
        return AUTH_RES_TITLE + token;
    }

    /** 解析token，返回token中的用户信息 */
    public static String parseToken(String token) {
        JWT jwt = JWTUtil.parseToken(token);
        JWTPayload payload = jwt.getPayload();
        return String.valueOf(payload.getClaim("uid"));
    }

    /** 暴露token(清除载荷) **/
    public static String exportToken(String token) {
        // 获取真正的token
        return token.split(" ")[1];
    }

    /** 根据过期时间判断是否需要续签 **/
    public static boolean isRenew(LoginUserDetail loginUserDetail) {
        LocalDateTime expireTime = loginUserDetail.getExpireTime();
        LocalDateTime now = LocalDateTime.now();
        // 计算（剩余时间 / 总时间）   2/10 = 0.2
        BigDecimal result = new BigDecimal(Duration.between(now, expireTime).toNanos())
                .divide(new BigDecimal(TIME_UNIT.toNanos(EXPIRATION_TIME)), 2, RoundingMode.DOWN);
        // now expireTime && 0.25 > 0.2 即可续签
        return now.isBefore(expireTime) && THRESHOLD.compareTo(result) > 0;
    }

}
